package com.wwg.util;

import com.google.common.base.Stopwatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @description ZIP压缩工具类
 * @systemName 融资平台
 * @author yyh  
 * @date 2019年12月13日   下午4:38:19 
 * @version V1.0   
 */  
public class ZipUtil {
	private static Logger LOGGER = LoggerFactory.getLogger(ZipUtil.class);
    private static final int  BUFFER_SIZE = 2 * 1024;
      
    /**  
     * @description 压缩文件  
     * @param srcDir 需要压缩的文件目录
     * @param os 压缩文件输出流
     * @param keepDirStructure 是否保留原来的目录结构:true-保留目录结构,false-所有文件跑到压缩包根目录下(注意：不保留目录结构可能会出现同名文件,会压缩失败)
     * @throws RuntimeException
     * @author yyh  
     * @date 2019年12月13日   下午4:43:08
     */  
    public static void toZip(String srcDir, OutputStream os, boolean keepDirStructure) throws RuntimeException{
        Stopwatch stopwatch = Stopwatch.createStarted();
        try(ZipOutputStream zos = new ZipOutputStream(os)){
            File sourceFile = new File(srcDir);
            compress(sourceFile,zos,sourceFile.getName(),keepDirStructure);
            long elapsed = stopwatch.elapsed(TimeUnit.MILLISECONDS);
            if(LOGGER.isDebugEnabled()){
            	LOGGER.debug("压缩完成，耗时:{}ms",elapsed);
            }
        } catch (Exception e) {
            throw new RuntimeException("zip error from ZipUtil",e);
        }
    }

    /**
     * 压缩成ZIP 方法
     * @param srcFiles 需要压缩的文件列表
     * @param os 压缩文件输出流
     * @throws RuntimeException 压缩失败会抛出运行时异常
     */
    public static void toZip(List<File> srcFiles , OutputStream os)throws RuntimeException {
    	Stopwatch stopwatch = Stopwatch.createStarted();
        try(ZipOutputStream zos = new ZipOutputStream(os) ){
            for (File srcFile : srcFiles) {
                byte[] buf = new byte[BUFFER_SIZE];
                zos.putNextEntry(new ZipEntry(srcFile.getName()));
                int len;
                try( FileInputStream in = new FileInputStream(srcFile)){
                	 while ((len = in.read(buf)) != -1){
                         zos.write(buf, 0, len);
                     }
                }
                zos.closeEntry();
               // in.close();
            }
            long elapsed = stopwatch.elapsed(TimeUnit.MILLISECONDS);
            if(LOGGER.isDebugEnabled()){
            	LOGGER.debug("压缩完成，耗时:{}ms",elapsed);
            }
        } catch (Exception e) {
            throw new RuntimeException("zip error from ZipUtil",e);
        }
    }

    /**
     * 递归压缩方法
     * @param sourceFile 源文件
     * @param zos zip输出流
     * @param name 压缩后的名称
     * @param keepDirStructure 是否保留原来的目录结构:true-保留目录结构,false-所有文件跑到压缩包根目录下(注意：不保留目录结构可能会出现同名文件,会压缩失败)
     * @throws Exception
     */
    private static void compress(File sourceFile, ZipOutputStream zos, String name, boolean keepDirStructure) throws Exception{
        byte[] buf = new byte[BUFFER_SIZE];
        if(sourceFile.isFile()){
            // 向zip输出流中添加一个zip实体，构造器中name为zip实体的文件的名字
            zos.putNextEntry(new ZipEntry(name));
            // copy文件到zip输出流中
            int len;
            try(FileInputStream in = new FileInputStream(sourceFile)){
            	 while ((len = in.read(buf)) != -1){
                     zos.write(buf,0 , len);
                 }
            }
            zos.closeEntry();
           // in.close();
        } else {
            File[] listFiles = sourceFile.listFiles();
            if(listFiles == null || listFiles.length ==0 ){
                // 需要保留原来的文件结构时,需要对空文件夹进行处理
                if(keepDirStructure){
                    // 空文件夹的处理
                    zos.putNextEntry(new ZipEntry(name + File.separator));
                    // 没有文件，不需要文件的copy
                    zos.closeEntry();
                }
            }else {
                for (File file : listFiles) {
                    // 判断是否需要保留原来的文件结构
                    if (keepDirStructure) {
                        // 注意：file.getName()前面需要带上父文件夹的名字加一斜杠,
                        // 不然最后压缩包中就不能保留原来的文件结构,即：所有文件都跑到压缩包根目录下了
                        compress(file, zos, name + File.separator + file.getName(),keepDirStructure);
                    } else {
                        compress(file, zos, file.getName(),keepDirStructure);
                    }
                }
            }
        }
    }


}